package command

import (
	"encoding/json"
	"fmt"
	"time"

	"gitee.com/xiaoyutab/sql-backups/config"
	"gitee.com/xiaoyutab/sql-backups/model"
	"gitee.com/xiaoyutab/xgotool/xnum"
	"gitee.com/xiaoyutab/xgotool/xstring"
	"github.com/glebarez/sqlite"
	"gorm.io/gorm"
)

// 备份数据库
func back(help bool) string {
	if help {
		return "备份数据库"
	}
	fmt.Println("开始执行备份")
	switch config.GetConfig().FromType {
	case "mysql":
		back_mysql()
	}
	fmt.Println("备份脚本执行完成")
	return ""
}

// MySQL数据库备份
func back_mysql() {
	fmt.Println("开始执行MySQL备份")
	defer fmt.Println("MySQL备份完成")
	st := config.GetStatus()
	now := time.Now()
	st.StartTime = time.Now().Format(time.DateTime)
	// 循环配置项
	mysql := config.GetConfig().MySQL
	for i := 0; i < len(mysql); i++ {
		dns := config.GetMysqlDns(mysql[i])
		fmt.Println("开始备份数据库：", dns)
		if st.Stat == nil {
			st.Stat = map[string]config.BackupsStatus{}
		}
		// 获取连接
		con, err := config.GetConnect("mysql", dns)
		if err != nil {
			fmt.Println("数据库连接失败：", err)
		}
		// 获取需要备份的表结构
		for j := 0; j < len(mysql[i].Backups); j++ {
			if mysql[i].Backups[j].Table == "" {
				continue
			}
			if _, ok := st.Stat[mysql[i].Databases+":"+mysql[i].Backups[j].Table]; !ok {
				st.Stat[mysql[i].Databases+":"+mysql[i].Backups[j].Table] = config.BackupsStatus{}
			}
			// 删除历史数据
			if mysql[i].Backups[j].IsDelete == 1 {
				l := map[string]any{}
				// 如果历史数据需要删除的话
				con.Table(mysql[i].Backups[j].Table).
					Where(mysql[i].Backups[j].ID+" <= ?", st.Stat[mysql[i].Databases+":"+mysql[i].Backups[j].Table].Id).
					Delete(&l)
				// 优化对应数据表
				// 因优化时太过于吃资源
				// 所以此处不再着重优化存储结构，而是只有在夜间的时候才会执行优化
				// 22~4点之间 且 分钟数在10分钟前 - 整理SQL数据库
				if xnum.InArray(time.Now().Hour(), []int{22, 23, 24, 0, 1, 2, 3, 4}) && time.Now().Minute() < 10 {
					con.Exec("OPTIMIZE TABLE `" + mysql[i].Backups[j].Table + "`")
				}
			}
			fmt.Println("开始备份表：", mysql[i].Backups[j].Table)
			// 获取备份的表信息
			db := con.Table(mysql[i].Backups[j].Table).
				Where(mysql[i].Backups[j].ID+" > ?", st.Stat[mysql[i].Databases+":"+mysql[i].Backups[j].Table].Id)
			if mysql[i].Backups[j].CTimes != "" {
				// 时间不为空
				db.Where(mysql[i].Backups[j].CTimes+" <= ?", time.Now().AddDate(0, 0, 0-mysql[i].Backups[j].Times).Format(time.DateOnly))
			} else if mysql[i].Backups[j].CTimeUnix != "" {
				// 时间戳不为空
				db.Where(mysql[i].Backups[j].CTimeUnix+" <= ?", time.Now().AddDate(0, 0, 0-mysql[i].Backups[j].Times).Unix())
			} else {
				fmt.Printf("数据库%s备份表[%s]的判定字段为空\n", dns, mysql[i].Backups[j].Table)
				continue
			}
			// 查询数据
			lists := []map[string]any{}
			err := db.Order(mysql[i].Backups[j].ID + " ASC").Limit(config.GetConfig().MaxLimit).Find(&lists).Error
			if err != nil {
				fmt.Printf("数据库%s备份表[%s]的查询结果错误：%s\n", dns, mysql[i].Backups[j].Table, err.Error())
			}
			for k := 0; k < len(lists); k++ {
				back_insert(mysql[i].Databases, mysql[i].Backups[j].Table, mysql[i].Backups[j].ID, lists[k])
				st.Stat[mysql[i].Databases+":"+mysql[i].Backups[j].Table] = config.BackupsStatus{
					Id:    xstring.Any2Integer(lists[k][mysql[i].Backups[j].ID]),
					Table: mysql[i].Backups[j].Table,
				}
			}
			fmt.Println("表", mysql[i].Backups[j].Table, "备份完成")
		}
	}
	st.RunTime = time.Since(now).Milliseconds()
	config.SetStatus(st)
}

// sqlite数据库写入数据
func back_insert(dns, table, pk string, ins map[string]any) {
	file_name := fmt.Sprintf("%s_%s.db", config.GetConfig().FileName, time.Now().Format(time.DateOnly))
	gorm, err := gorm.Open(sqlite.Open(file_name))
	if err != nil {
		panic(err)
	}
	// 创建迁移表信息
	gorm.AutoMigrate(&model.BackTable{})
	// json转码
	j, _ := json.Marshal(ins)
	// 数据插入
	err = gorm.Create(&model.BackTable{
		Id:           time.Now().UnixMilli(),
		Dns:          dns,
		Table:        table,
		TableId:      xstring.Any2Integer(ins[pk]),
		TableContent: string(j),
		CreatedAt:    time.Now().Format(time.DateTime),
	}).Error
	if err != nil {
		fmt.Println("sqlite数据库插入失败", err)
	}
}
